home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / program / mkdpnd11.lha / MkDepend-1.1 / reader.c < prev    next >
C/C++ Source or Header  |  1995-10-14  |  14KB  |  632 lines

  1. /*
  2. $VER: reader:c 1.1 (13-Oct-95) Copyright © by Lars Düning
  3. */
  4.  
  5. /*---------------------------------------------------------------------------
  6. ** Reading of C-Sources and filter for #include statements.
  7. ** Also here are routines for the modification of Makefiles.
  8. **
  9. ** Copyright © 1995  Lars Düning  -  All rights reserved.
  10. ** Permission granted for non-commercial use.
  11. **---------------------------------------------------------------------------
  12. ** Credits:
  13. **   The buffering scheme was inspired by the input module of lcc (by
  14. **   Chris Fraser & David Hanson).
  15. **---------------------------------------------------------------------------
  16. ** C: DICE 3.01
  17. **---------------------------------------------------------------------------
  18. ** [lars] Lars Düning; Am Wendenwehr 25; D-38114-Braunschweig;
  19. **                     Germany; Tel. 49-531-345692
  20. **---------------------------------------------------------------------------
  21. ** 10-Sep-95 [lars]
  22. ** 13-Oct-95 [lars] reader_copymake2() new, to copy the file remainder.
  23. ** 13-Oct-95 [lars] current
  24. **---------------------------------------------------------------------------
  25. */
  26.  
  27. #include <assert.h>
  28. #include <fcntl.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <sys/types.h>
  32. #include "reader.h"
  33.  
  34. /*-------------------------------------------------------------------------*/
  35.  
  36. struct filestate
  37.  {
  38.   int len;      /* Number of bytes buffered */
  39.   char buf[1];  /* allocated to <len> bytes */
  40.  };
  41.  
  42. #define BUFSIZE 10240              /* Size of the file buffer */
  43. static char   aBuffer[BUFSIZE+1];  /* File buffer */
  44. static int    fdFile;              /* Filehandle */
  45. static int    fdFile2;             /* Filehandle Writer */
  46. static char * pLimit;              /* Pointer to closing sentinel in buffer */
  47. static char * pch;                 /* Pointer to actual char in buffer */
  48. static char * pIName;              /* Start of include filename */
  49. static struct filestate * pState;  /* Saved state of the Makefile */
  50.  
  51. #define END_OF_BUF()  (pch >= pLimit)
  52. #define END_OF_FILE() (pLimit == aBuffer)
  53.  
  54. /*-------------------------------------------------------------------------*/
  55. void
  56. reader_init (void)
  57.  
  58. /* Initialize the reader.
  59.  */
  60.  
  61. {
  62.   fdFile = -1;
  63.   fdFile2 = -1;
  64.   aBuffer[BUFSIZE] = '\n';
  65.   pLimit = aBuffer+BUFSIZE;
  66.   pch = pLimit;
  67.   pIName = NULL;
  68.   pState = NULL;
  69. }
  70.  
  71. /*-------------------------------------------------------------------------*/
  72. static int
  73. fillbuffer (void)
  74.  
  75. /* Read in the next chunk from file such that incrementing pch will
  76.  * access the newly read data.
  77.  *
  78.  * Result:
  79.  *   0 on success, non-0 else (errno holds error code then).
  80.  *   pch is set to the start of the new data.
  81.  */
  82.  
  83. {
  84.   int iRead;
  85.  
  86.   if (END_OF_FILE())
  87.     return 1;
  88.   if (pIName)
  89.   {
  90.     if (pch > pLimit)
  91.       pch = pLimit;
  92.     memcpy(aBuffer, pIName, pLimit-pIName);
  93.     pch -= (pLimit-pIName);
  94.   }
  95.   else
  96.     pch = aBuffer;
  97.   iRead = read(fdFile, pch, aBuffer+BUFSIZE-pch);
  98.   if (iRead >= 0)
  99.   {
  100.     pLimit = pch+iRead;
  101.     *pLimit = '\n';
  102.   }
  103.   return iRead < 0;
  104. }
  105.  
  106. /*-------------------------------------------------------------------------*/
  107. int
  108. reader_open (const char *pName)
  109.  
  110. /* Open a file for reading.
  111.  *
  112.  *   pName: Name of the file to read.
  113.  *
  114.  * Result:
  115.  *   0 on success, non-0 else (errno contains error code then).
  116.  *
  117.  * The reader is initialized to read and filter the file name *pName.
  118.  */
  119.  
  120. {
  121.   assert(pName);
  122.   assert(fdFile < 0);
  123.   reader_init();
  124.   fdFile = open(pName, O_RDONLY);
  125.   return fdFile >= 0;
  126. }
  127.  
  128. /*-------------------------------------------------------------------------*/
  129. int
  130. reader_openrw (const char *pNameR, const char *pNameW)
  131.  
  132. /* Open two makefiles for modification.
  133.  *
  134.  *   pNameR: Name of the file to read, may be NULL.
  135.  *   pNameW: Name of the file to read.
  136.  *
  137.  * Result:
  138.  *   0 on success, non-0 else (errno contains error code then).
  139.  *
  140.  * The reader is initialized to read the old makefile *pNameR and writing
  141.  * of new makefile *pNameW.
  142.  */
  143.  
  144. {
  145.   assert(pNameW);
  146.   assert(fdFile < 0);
  147.   assert(fdFile2 < 0);
  148.   reader_init();
  149.   fdFile2 = open(pNameW, O_WRONLY|O_CREAT|O_TRUNC);
  150.   if (fdFile2 < 0)
  151.     return 1;
  152.   if (pNameR)
  153.   {
  154.     fdFile = open(pNameR, O_RDONLY);
  155.     if (fdFile < 0)
  156.     {
  157.       close(fdFile2);
  158.       fdFile2 = -1;
  159.     }
  160.   }
  161.   return fdFile2 < 0;
  162. }
  163.  
  164. /*-------------------------------------------------------------------------*/
  165. int
  166. reader_close (void)
  167.  
  168. /* Close the file currently read.
  169.  * Result:
  170.  *   0 on success, non-0 else.
  171.  *   errno set to error code in case.
  172.  */
  173.  
  174. {
  175.   int i;
  176.  
  177.   i = 0;
  178.   if (fdFile >= 0)
  179.   {
  180.     i = close(fdFile);
  181.   }
  182.   fdFile = -1;
  183.   if (fdFile2 >= 0)
  184.   {
  185.     i = close(fdFile2) || i;
  186.   }
  187.   fdFile2 = -1;
  188.   if (pState)
  189.   {
  190.     free(pState);
  191.   }
  192.   pState = NULL;
  193.   return i;
  194. }
  195.  
  196. /*-------------------------------------------------------------------------*/
  197. int
  198. reader_eof (void)
  199.  
  200. /* Test if the file read is at its end.
  201.  *
  202.  * Result:
  203.  *   Non-0 on end of file.
  204.  */
  205.  
  206. {
  207.   return END_OF_FILE();
  208. }
  209.  
  210. /*-------------------------------------------------------------------------*/
  211. const char *
  212. reader_get (void)
  213.  
  214. /* Extract the next include statement from the file being read.
  215.  *
  216.  * Result:
  217.  *   Pointer to the filename extracted from the statement, or NULL on error
  218.  *     or end of file.
  219.  *     The memory is property of reader_get(), the pointer valid just until
  220.  *     the next call to reader_get().
  221.  *   errno set to an error code in case.
  222.  */
  223.  
  224. {
  225.   enum { StartOfLine, InLine, FoundHash, SkipComment, SkipLComment, FoundInclude
  226.       }  eState;
  227.   char   *stab[]
  228.     = {
  229.         "Start "
  230.       , "InLine"
  231.       , "Found#"
  232.       , "SkipC "
  233.       , "SkipLC"
  234.       , "FoundI"
  235.       };
  236.   char   ch;
  237.   int    iFound; /* Number of chars found of "include" */
  238.   int    bDone;
  239.  
  240. #define GETCHAR() \
  241.   ch = *pch++; \
  242.   if (ch == '\n' && pch >= pLimit) \
  243.   { \
  244.     if (fillbuffer()) { \
  245.       pIName = NULL; \
  246.       return NULL; \
  247.     } \
  248.     ch = *pch++; \
  249.   }
  250.  
  251.   if (pIName)
  252.     eState = InLine;
  253.   else
  254.     eState = StartOfLine;
  255.   pIName = NULL;
  256.  
  257.   bDone = 0;
  258.   while (!bDone)
  259.   {
  260.     /* Get the next interesting non-linefeed character */
  261.     do {
  262.       GETCHAR()
  263.       if (ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f')
  264.       {
  265.         eState = StartOfLine;
  266.         pIName = NULL;
  267.       }
  268.       else
  269.         break;
  270.     } while (1);
  271.  
  272.     switch(eState)
  273.     {
  274.     case StartOfLine:
  275.       switch (ch)
  276.       {
  277.       case '#':
  278.         eState = FoundHash;
  279.         iFound = 0;
  280.         break;
  281.       case '/':
  282.         GETCHAR()
  283.         if (ch == '/')
  284.           eState = SkipLComment;
  285.         else if (ch == '*')
  286.           eState = SkipComment;
  287.         else
  288.           eState = InLine;
  289.         break;
  290.       case ' ': case '\t':
  291.         /* still: eState = StartOfLine; */
  292.         break;
  293.       default:
  294.         eState = InLine;
  295.         break;
  296.       }
  297.       break;
  298.  
  299.     case InLine:
  300.       switch (ch)
  301.       {
  302.       case '/':
  303.         GETCHAR()
  304.         if (ch == '/')
  305.           eState = SkipLComment;
  306.         else if (ch == '*')
  307.           eState = SkipComment;
  308.         else
  309.           eState = InLine;
  310.         break;
  311.       case '\\':
  312.         GETCHAR()
  313.         /* still: eState = InLine; */
  314.         break;
  315.       default:
  316.         /* still: eState = InLine; */
  317.         break;
  318.       }
  319.       break;
  320.  
  321.     case FoundHash:
  322.       switch(ch)
  323.       {
  324.       case ' ': case '\t':
  325.         if (iFound)
  326.         {
  327.           eState = InLine;
  328.           iFound = 0;
  329.         }
  330.         /* else still: eState = FoundHash */
  331.         break;
  332.       case 'i': case 'n': case 'c': case 'l':
  333.       case 'u': case 'd': case 'e':
  334.         if ("include"[iFound] != ch)
  335.         {
  336.           eState = InLine;
  337.           iFound = 0;
  338.         }
  339.         else if (ch == 'e')
  340.         {
  341.           eState = FoundInclude;
  342.           pIName = NULL;
  343.         }
  344.         else
  345.           iFound++;
  346.         break;
  347.       default:
  348.         eState = InLine;
  349.       }
  350.       break;
  351.  
  352.     case FoundInclude:
  353.       switch(ch)
  354.       {
  355.       case ' ': case '\t':
  356.         /* still: eState = FoundInclude */
  357.         break;
  358.       case '<':
  359.         if (!pIName)
  360.         {
  361.           eState = InLine;
  362.         }
  363.         break;
  364.       case '"':
  365.         if (!pIName)
  366.         {
  367.           pIName = pch;
  368.         }
  369.         else
  370.         {
  371.           *(pch-1) = '\0';
  372.           if (pch-1 == pIName)
  373.             pIName = NULL;
  374.           else
  375.             bDone = 1;
  376.           eState = InLine;
  377.         }
  378.         break;
  379.  
  380.       default:
  381.         if (!pIName)
  382.           eState = InLine;
  383.         break;
  384.       }
  385.       break;
  386.  
  387.     } /* switch (eState) */
  388.  
  389.     /* Skip comments immediately */
  390.     if (eState == SkipComment)
  391.     {
  392.       while(1) {
  393.         do {
  394.           GETCHAR()
  395.         } while (ch != '*');
  396.         GETCHAR()
  397.         if (ch == '/')
  398.         break;
  399.       }
  400.       eState = StartOfLine;
  401.     }
  402.     else if (eState == SkipLComment)
  403.     {
  404.       do {
  405.         GETCHAR()
  406.       } while (ch != '\n' && ch != '\r' && ch != '\v' && ch != '\f');
  407.       eState = StartOfLine;
  408.     }
  409.   } /* while(!bDone) */
  410.   return pIName;
  411.  
  412. #undef GETCHAR
  413. }
  414.  
  415. /*-------------------------------------------------------------------------*/
  416. int
  417. reader_writeflush (void)
  418.  
  419. /* Write out the buffer to the written makefile.
  420.  * Return 0 on success, non-0 else (errno holds the error code then).
  421.  */
  422.  
  423. {
  424.   if (pch > aBuffer && write(fdFile2, aBuffer, pch-aBuffer) != pch-aBuffer)
  425.     return 1;
  426.   pch = aBuffer;
  427.   return 0;
  428. }
  429.  
  430. /*-------------------------------------------------------------------------*/
  431. int
  432. reader_writen (const char *pText, int len)
  433.  
  434. /* Append the first <len> characters of <pText> to the written file.
  435.  * Return 0 on success, non-0 else (errno holds the error code then)
  436.  */
  437.  
  438. {
  439.   assert(pText);
  440.   assert(fdFile2 >= 0);
  441.   if (pLimit-pch < len && reader_writeflush())
  442.     return 1;
  443.   memcpy(pch, pText, len);
  444.   pch += len;
  445.   return 0;
  446. }
  447.  
  448. /*-------------------------------------------------------------------------*/
  449. int
  450. reader_write (const char *pText)
  451.  
  452. /* Append <pText> to the written file.
  453.  * Return 0 on success, non-0 else (errno holds the error code then)
  454.  */
  455.  
  456. {
  457.   return reader_writen(pText, strlen(pText));
  458. }
  459.  
  460. /*-------------------------------------------------------------------------*/
  461. int
  462. reader_copymake (const char * pTagline)
  463.  
  464. /* Copy the file from fdFile to fdFile2 up to including the tagline.
  465.  * If the tagline is not found, it is appended.
  466.  * The tagline MUST end in a newline character!
  467.  * Return 0 on success, non-0 on error (errno holds the error code then).
  468.  */
  469.  
  470. {
  471.   int len;
  472.   int count; /* Next charactor to compare in pTagline, or -1 if to skip
  473.               * up to the next Newline */
  474.   char ch;
  475.  
  476.  
  477.   assert(pTagline);
  478.   assert(fdFile2);
  479.   len = strlen(pTagline);
  480.   assert(len < 120);
  481.  
  482.   /* Simplest case: no old makefile to copy */
  483.   if (fdFile < 0)
  484.   {
  485.     strcpy(aBuffer, pTagline);
  486.     pch = aBuffer+len;
  487.     return 0;
  488.   }
  489.   if (fillbuffer())
  490.     return 1;
  491.   count = 0;
  492.  
  493.   while (!END_OF_FILE() && count < len)
  494.   {
  495.     if (END_OF_BUF())
  496.     {
  497.       if (write(fdFile2, aBuffer, pch-aBuffer) != pch-aBuffer)
  498.         return 1;
  499.       if (fillbuffer())
  500.         return 1;
  501.       if (END_OF_FILE())
  502.         break;
  503.     }
  504.     ch = *pch;
  505.     if (count < 0)
  506.     {
  507.       if (ch == '\n')
  508.         count = 0;
  509.     }
  510.     else
  511.     {
  512.       if (ch == pTagline[count])
  513.         count++;
  514.       else if (ch == '\n')
  515.         count = 0;
  516.       else
  517.         count = -1;
  518.     }
  519.     pch++;
  520.   }
  521.  
  522.   /* Remember the state of the Makefile read */
  523.   if (!END_OF_FILE())
  524.   {
  525.     pState = (struct filestate *) malloc(sizeof(*pState)+(pLimit-pch));
  526.     if (pState)
  527.     {
  528.       pState->len = pLimit-pch;
  529.       memcpy(pState->buf, pch, pState->len);
  530.     }
  531.   }
  532.  
  533.   /* Switch to write mode */
  534.   pLimit = aBuffer+BUFSIZE;
  535.  
  536.   /* Append a newline if missing */
  537.   if (count < 0 && reader_writen("\n", 1))
  538.     return 1;
  539.  
  540.   /* Put the Tagline into the buffer if necessary */
  541.   if (count < len && reader_writen(pTagline, len))
  542.     return 1;
  543.  
  544.   return 0;
  545. }
  546.  
  547. /*-------------------------------------------------------------------------*/
  548. int
  549. reader_copymake2 (const char * pTagline)
  550.  
  551. /* Copy the remainder from fdFile to fdFile2 starting with the tagline.
  552.  * The tagline MUST end in a newline character!
  553.  * Return 0 on success, non-0 on error (errno holds the error code then).
  554.  */
  555.  
  556. {
  557.   int len;
  558.   int count; /* Next charactor to compare in pTagline, or -1 if to skip
  559.               * up to the next Newline */
  560.   char ch;
  561.  
  562.  
  563.   assert(pTagline);
  564.   assert(fdFile);
  565.   assert(fdFile2);
  566.   len = strlen(pTagline);
  567.   assert(len < 120);
  568.  
  569.   /* Append the tagline to the file written */
  570.   if (reader_write(pTagline) || reader_writeflush())
  571.     return 1;
  572.  
  573.   /* Easiest case: nothing to left copy */
  574.   if (!pState)
  575.     return 0;
  576.  
  577.   /* Restore the aBuffer to the point where the reading stopped */
  578.   pLimit = aBuffer+BUFSIZE;
  579.   pch = pLimit-pState->len;
  580.   memcpy(pch, pState->buf, pState->len);
  581.   free(pState);
  582.   pState = NULL;
  583.   pIName = NULL;
  584.  
  585.   /* Fill up the buffer */
  586.   if (END_OF_BUF() && fillbuffer())
  587.     return 1;
  588.  
  589.   /* Skip the Makefile read until the tagline has been found */
  590.   count = 0;
  591.   while (!END_OF_FILE() && count < len)
  592.   {
  593.     if (END_OF_BUF())
  594.     {
  595.       if (fillbuffer())
  596.         return 1;
  597.       if (END_OF_FILE())
  598.         break;
  599.     }
  600.     ch = *pch;
  601.     if (count < 0)
  602.     {
  603.       if (ch == '\n')
  604.         count = 0;
  605.     }
  606.     else
  607.     {
  608.       if (ch == pTagline[count])
  609.         count++;
  610.       else if (ch == '\n')
  611.         count = 0;
  612.       else
  613.         count = -1;
  614.     }
  615.     pch++;
  616.   }
  617.  
  618.   /* Copy the remainder of the Makefile */
  619.   do
  620.   {
  621.     if (!END_OF_BUF() && write(fdFile2, pch, pLimit-pch) != pLimit-pch)
  622.       return 1;
  623.     if (!END_OF_FILE() && fillbuffer())
  624.       return 1;
  625.   }
  626.   while (!END_OF_FILE());
  627.  
  628.   return 0;
  629. }
  630.  
  631. /***************************************************************************/
  632.